package com.hengpeng.itfin.service.investinfo.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.hengpeng.common.exception.ServiceResult;
import com.hengpeng.common.persist.query.DynamicQuery;
import com.hengpeng.common.util.DateTimeUtil;
import com.hengpeng.common.util.MoneyUtil;
import com.hengpeng.itfin.common.SystemConfigUtil;
import com.hengpeng.itfin.service.impl.BaseServiceImpl;
import com.hengpeng.itfin.service.investinfo.InvestInfoService;
import com.hengpeng.itfinbase.constants.RespCodeConstants;
import com.hengpeng.itfinbase.constants.SystemConfigConstants;
import com.hengpeng.itfinbase.constants.TransCodeConstants;
import com.hengpeng.itfinbase.en.AccountType;
import com.hengpeng.itfinbase.en.ActivityType;
import com.hengpeng.itfinbase.en.BorrowStatus;
import com.hengpeng.itfinbase.en.InvestStatus;
import com.hengpeng.itfinbase.en.RewardRedPacketStatus;
import com.hengpeng.itfinbase.en.TradeMode;
import com.hengpeng.itfinbase.en.TransType;
import com.hengpeng.itfinbase.idAssign.ID;
import com.hengpeng.itfinbase.message.ResponseMessage;
import com.hengpeng.itfinbase.message.activity.InvestBackRebateRequest;
import com.hengpeng.itfinbase.message.activity.InvestRedPacketRequest;
import com.hengpeng.itfinbase.message.partner.InvestInfoRequestMsg;
import com.hengpeng.itfinbase.message.partner.InvestInfoResponseMsg;
import com.hengpeng.itfinbase.message.partner.PartnerTransType;
import com.hengpeng.itfinbase.message.partner.QueryTransStatRequest;
import com.hengpeng.itfinbase.message.partner.QueryTransStatResponse;
import com.hengpeng.itfinbase.message.partner.TransferRequest;
import com.hengpeng.itfinbase.persist.Account;
import com.hengpeng.itfinbase.persist.BorrowInfo;
import com.hengpeng.itfinbase.persist.InvestInfo;
import com.hengpeng.itfinbase.persist.RewardRedpacket;
import com.hengpeng.itfinbase.persist.UserInfo;

@Service
@Lazy
@Transactional
public class InvestInfoServiceImpl extends BaseServiceImpl implements InvestInfoService {

    private static final String MDT000001 = "MDT000001";// 托管子账户名

    @Override
    public InvestInfo getInvestByUnFreeOrderId(String unFreeOrderId, boolean isLock) {
        DynamicQuery query = new DynamicQuery(InvestInfo.class);
        query.eq("unFreeOderId", unFreeOrderId);
        InvestInfo investInfo = serviceFactory.getPersistService().getByDynamicQuery(InvestInfo.class, query);
        if (isLock && investInfo != null) {
            investInfo = serviceFactory.getPersistService().lockObject(InvestInfo.class, investInfo.getId());
        }
        return investInfo;
    }

    /**
     * <pre>
     *  投资接口调用成功后操作：
     *                        1,更新投资信息状态 
     *                        2,冻结投资人资金信息表中相关资金。 
     *                        3,添加资金流水表相关资金冻结流水。
     *                        4,判断投标总金额是否已经达到募集金额，如果达到募集金额则设置标的状态为：募集结束
     *  投资接口调用失败后操作：
     *                        1,释放投资额度,更新标的信息表中的已募集金额,已募集人数。 
     *                        2,更新投标信息状态为：失败
     * </pre>
     */
    @Override
    public ServiceResult<String> dealInvestResult(InvestInfoResponseMsg response) {
        ServiceResult<String> result = new ServiceResult<String>();
        if (response == null || !RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode())) {
            result.setIsSuccess(false);
            // 失败
            InvestInfo investInfo = serviceFactory.getDaoFactory().getInvestInfoDao()
                    .get(Long.parseLong(response.getOrdId()));
            if (investInfo != null && investInfo.getStatus().equals(InvestStatus.INVESTING)) {
                int i = serviceFactory.getDaoFactory().getInvestInfoDao()
                        .updateStatus(investInfo.getId(), InvestStatus.INVESTING, InvestStatus.FAILURE);
                if (i > 0) {
                    BorrowInfo borrowInfo = serviceFactory.getDaoFactory().getBorrowInfoDao()
                            .get(investInfo.getBorrowInfoId());
                    if (borrowInfo != null && borrowInfo.getStatus().equals(BorrowStatus.RAISE)) {
                        // 释放额度
                        borrowInfo.setRaiseMoney(borrowInfo.getRaiseMoney() - investInfo.getInvestMoney());
                        borrowInfo.setRaiseNum(borrowInfo.getRaiseNum() - 1);
                        serviceFactory.getDaoFactory().getBorrowInfoDao().update(borrowInfo);
                    } else {
                        result.setMessage(RespCodeConstants.BorrowInfoCode.BORROWINFO_UNKONW_MSG);
                        result.setCode(RespCodeConstants.BorrowInfoCode.BORROWINFO_UNKONW);
                    }
                }
            } else {
                result.setMessage(RespCodeConstants.CommonCode.TRANS_FAIL);
                result.setCode(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
            }
            return result;
        } else if (RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode())) {
            // 成功
            InvestInfo investInfo = serviceFactory.getDaoFactory().getInvestInfoDao()
                    .get(Long.parseLong(response.getOrdId()));
            if (investInfo != null && investInfo.getStatus().equals(InvestStatus.INVESTING)) {
                int i = serviceFactory
                        .getDaoFactory()
                        .getInvestInfoDao()
                        .updateStatusAndFreeId(investInfo.getId(), response.getFreezeTrxId(), InvestStatus.INVESTING,
                                InvestStatus.SUCESS);
                if (i > 0) {
                    investInfo.setFreezeTrxId(response.getFreezeTrxId());// 设置冻结标识
                    investInfo.setStatus(InvestStatus.SUCESS);

                    /**
                     * <pre>
                     * 投资成功进行红包划账处理：
                     *  1,更新使用的红包状态 
                     *  2,生成红包使用日志 
                     *  3,调用转账接口转账
                     * </pre>
                     * 
                     */
                    RewardRedpacket redpacket = serviceFactory.getDaoFactory().getRedPacketDao()
                            .get(investInfo.getRedPacketId());
                    int j = serviceFactory
                            .getDaoFactory()
                            .getRedPacketDao()
                            .updateStatus(investInfo.getRedPacketId(), RewardRedPacketStatus.CANUSE,
                                    RewardRedPacketStatus.USEED, new Date());
                    if (j > 0) {
                        // 入账账户
                        Account inAccount = serviceFactory.getDaoFactory().getAccountDao()
                                .getAccountByUserId(investInfo.getInvestUserId());
                        // 出账用户
                        UserInfo outUser = serviceFactory
                                .getDaoFactory()
                                .getUserInfoDao()
                                .get(Long.parseLong(SystemConfigUtil
                                        .getConfigValue(SystemConfigConstants.PARTNER_USERID)));
                        // 出账账户
                        Account outAccount = serviceFactory.getDaoFactory().getAccountDao()
                                .getAccountByUserIdAndSub(outUser.getId(), MDT000001);
                        /**
                         * 调用划账接口
                         */
                        TransferRequest transferRequest = new TransferRequest();
                        transferRequest.setOutType(AccountType.PLATFORM);// 固定出账户只能是平台账户
                        transferRequest.setOutUserId(outUser.getId());
                        transferRequest.setOutCustId(outAccount.getTrustAccountId());
                        transferRequest.setOutAcctId(outAccount.getSubAccountId());
                        transferRequest.setInType(AccountType.PERSONAL);
                        transferRequest.setInUserId(investInfo.getInvestUserId());
                        transferRequest.setInCustId(inAccount.getTrustAccountId());
                        transferRequest.setInAcctId(inAccount.getSubAccountId());
                        transferRequest.setTransAmt(MoneyUtil.convertFenToYuan(redpacket.getMoney()));
                        transferRequest.setPartnerTransType(PartnerTransType.Transfer);
                        transferRequest.setTransType(TransCodeConstants.PartnerTransCode.REQUEST);
                        transferRequest.setReferenceId(redpacket.getId().toString());
                        transferRequest.setMerPriv("REDPACKETBACK");// 红包划账
                        serviceFactory.getPartnerService().request(transferRequest);
                        /**
                         * <pre>
                         * 转账成功,失败的处理,在转账回调接口中
                         * 成功:生成红包使用日志
                         * 失败:回退红包使用状态
                         * </pre>
                         */
                    }
                    BorrowInfo borrowInfo = serviceFactory.getDaoFactory().getBorrowInfoDao()
                            .get(investInfo.getBorrowInfoId());

                    /**
                     * 满标设置筹款结束
                     */
                    if (borrowInfo.getRaiseMoney().longValue() == borrowInfo.getBorrowMoney().longValue()) {
                        borrowInfo.setStatus(BorrowStatus.END);
                        serviceFactory.getDaoFactory().getBorrowInfoDao().update(borrowInfo);
                    }

                    /**
                     * 更新投资人资金信息,添加资金流水
                     */
                    serviceFactory.getAccountService().changeAccountMoney(investInfo.getInvestUserId(),
                            investInfo.getInvestMoney(), TransType.INVEST, TradeMode.FREEZE,
                            investInfo.getId().toString(), "投标成功");

                    /**
                     * 投标成功调用活动接口，投资送等额红包
                     */
                    InvestRedPacketRequest investRedPacketRequest = new InvestRedPacketRequest();
                    investRedPacketRequest.setUserId(investInfo.getInvestUserId());
                    investRedPacketRequest.setActivityType(ActivityType.INVEST_REDPACKET);
                    investRedPacketRequest.setRewardVal(investInfo.getInvestMoney() / 100);
                    investRedPacketRequest.setTransType(TransCodeConstants.ActivityTransCode.INVEST_SEND_REDPACKET);
                    serviceFactory.getPortActiveFactory().remoteTrans(investRedPacketRequest);
                    /**
                     * TODO 根据不同人的角色进行返利 投标成功调用活动接口,投资返利
                     */
                    UserInfo investUser = serviceFactory.getDaoFactory().getUserInfoDao()
                            .get(investInfo.getInvestUserId());
                    InvestBackRebateRequest investBackRebateRequest = new InvestBackRebateRequest();
                    investBackRebateRequest.setUserId(investInfo.getInvestUserId());
                    investBackRebateRequest.setActivityType(ActivityType.INVEST_REBATE);
                    investBackRebateRequest.setInvestMoney(investInfo.getInvestMoney());
                    investBackRebateRequest.setTransType(TransCodeConstants.ActivityTransCode.INVEST_SEND_REBATE);
                    serviceFactory.getPortActiveFactory().remoteTrans(investBackRebateRequest);
                }
                result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
                result.setMessage(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                result.setIsSuccess(true);
            } else {
                result.setIsSuccess(true);
                result.setMessage(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
            }
        }
        return result;
    }

    @Override
    public void investQuery() {
        try {
            List<InvestInfo> list = serviceFactory.getDaoFactory().getInvestInfoDao()
                    .queryList(null, new InvestStatus[] { InvestStatus.INVESTING });
            if (list != null && list.size() > 0) {
                List<Future<Long>> rtList = new ArrayList<Future<Long>>();
                ExecutorService execute = Executors.newFixedThreadPool(list.size());
                for (final InvestInfo iv : list) {
                    Future<Long> submit = execute.submit(new Callable<Long>() {
                        public Long call() {
                            try {
                                serviceFactory.getInvestInfoService().doInvestQuery(iv);
                            } catch (Throwable e) {
                                logger.error("投标状态查询线程异常", e);
                            }
                            return 0L;
                        }
                    });
                    rtList.add(submit);
                }
                execute.shutdown();
                for (Future<Long> future : rtList) {
                    future.get();
                }
            }
        } catch (Throwable e) {
            logger.error("投标状态查询线程异常", e);
        }
    }

    @Override
    public void doInvestQuery(InvestInfo investInfo) {
        Date time = DateTimeUtil.addSecond(investInfo.getCreateTime(),
                Long.parseLong(SystemConfigUtil.getConfigValue(SystemConfigConstants.INVEST_LIMIT_TIME)));
        if (time.getTime() < System.currentTimeMillis()) {
            /**
             * <pre>
             * 当投资人投标时,超过指定时间还未完成支付,则系统进行交易状态查询,
             * 查询结果若为交易失败,则进行释放融资额度操作
             * 查询结果若为交易成功,则进行交易信息的补充成功操作.
             * </pre>
             */
            QueryTransStatRequest request = new QueryTransStatRequest();
            request.setOrdId(investInfo.getFreeOderId());
            request.setOrdDate(DateTimeUtil.formatToStr(investInfo.getCreateTime(), DateTimeUtil.DATE_FORMAT_YYYYMMDD));
            request.setPartnerTransType(PartnerTransType.QueryTransStat);
            request.setQueryTransType("FREEZE");
            QueryTransStatResponse response = (QueryTransStatResponse) serviceFactory.getPartnerService().request(
                    request);
            if ("F".equals(response.getTransStat()) || "U".equals(response.getTransStat())) {
                final InvestInfoResponseMsg investResponse = new InvestInfoResponseMsg();
                investResponse.setOrdId(investInfo.getId().toString());
                if ("F".equals(response.getTransStat())) {// 成功冻结
                    investResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_SUC);
                    investResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                    investResponse.setFreezeTrxId(response.getTrxId());
                } else if ("U".equals(response.getTransStat())) {// 未冻结
                    investResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
                    investResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
                }
                ServiceResult<String> resulst = serviceFactory.getInvestInfoService().dealInvestResult(investResponse);
                logger.info("投标状态查询定时作业：投标id:" + investResponse.getOrdId() + ",响应消息:" + resulst.getMessage() + ",响应码:"
                        + resulst.getCode() + "");

            }
        }
    }

    @Override
    public ResponseMessage packInvestRequest(InvestInfoRequestMsg reqMsg) {
        ResponseMessage response = new ResponseMessage();
        /**
         * 借款前先占据借款额度
         */
        BorrowInfo borrowInfo = serviceFactory.getDaoFactory().getBorrowInfoDao()
                .getBorrowInfo(Long.parseLong(reqMsg.getBorrowInfoId()), BorrowStatus.RAISE);
        int i = serviceFactory.getDaoFactory().getBorrowInfoDao()
                .updateRaiseMoney(borrowInfo.getId(), Long.parseLong(reqMsg.getTransAmt()));
        if (i > 0) {
            UserInfo investUserInfo = serviceFactory.getPersistService().get(UserInfo.class,
                    Long.parseLong(reqMsg.getInvestUserId()));
            /**
             * 生成并保存投资信息
             */
            InvestInfo investInfo = new InvestInfo();
            investInfo.setUserLevel(investUserInfo.getUserLevel());
            investInfo.setInvestUserName(reqMsg.getInvestUserName());
            investInfo.setInvestUserId(Long.parseLong(reqMsg.getInvestUserId()));
            investInfo.setInvestUserTrustAccountId(reqMsg.getUsrCustId());
            investInfo.setNowOwnUserId(Long.parseLong(reqMsg.getInvestUserId()));
            investInfo.setNowOwnUserTrustAccountId(reqMsg.getUsrCustId());
            investInfo.setNowOwnUserName(reqMsg.getInvestUserName());
            investInfo.setBorrowInfoId(Long.parseLong(reqMsg.getBorrowInfoId()));
            investInfo.setBorrowName(reqMsg.getBorrowName());
            investInfo.setInvestMoney(Long.parseLong(reqMsg.getTransAmt()));
            investInfo.setRedPacketId(reqMsg.getRedPacketId());
            investInfo.setInvestTime(new Date());
            investInfo.setStatus(InvestStatus.INVESTING);
            investInfo.setCreateTime(new Date());
            investInfo.setUpdateTime(new Date());
            String freeOderId = ID.getInstanse().getID(18).toString();
            investInfo.setFreeOderId(freeOderId);
            investInfo = serviceFactory.getPersistService().save(investInfo);
            reqMsg.setInvestInfoId(investInfo.getId());
            reqMsg.setOrdDate(DateTimeUtil.formatToStr(new Date(), DateTimeUtil.DATE_FORMAT_YYYYMMDD));
            reqMsg.setFreezeOrdId(freeOderId);
        } else {
            response.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
            response.setRespDesc("借款额度已满");
        }
        return response;
    }
}
